/*:
* @plugindesc (v1.13)全场状态-战场属性系统.
* @author 小c
* @version 1.0.6
* @date 1/21/2020
*
* @param Default Global State Count Max
* @text 默认全场状态最大层数
* @type number
* @min 0
* @default 1
* @desc 这里0表示无限层数
*
* @param Element List
* @text 战场属性列表
* @type struct<elementData>[]
* @default []
*
* @param Element Total Count Function
* @text 战场属性层数变换函数
* @type note
* @default "return this.globalElementCount(elementId);"
* @desc 战场属性层数的运算函数，参数说明请看插件的说明文件。
*
* @param Element Count Text
* @text 战场属性提示文字
* @type struct<elementText>
* @default {"text":"%1+","font":"GameFont","size":"18"}
*
* @param Element Home X
* @text 战场属性中心X
* @type note
* @desc 召唤战场属性图标出现的默认位置，之后图标运动到显示属性状态的位置，参数：elementId
* @default "return Graphics.boxWidth / 2;"
*
* @param Element Home Y
* @text 战场属性中心Y
* @type note
* @desc 召唤战场属性图标出现的默认位置，之后图标运动到显示属性状态的位置，参数：elementId
* @default "return Graphics.boxHeight / 2;"
*
* @param Element Move Time
* @text 召唤战场属性的运动时间
* @type number
* @default 60
* @desc 召唤战场属性的运动时间（帧）
*
* @param Element Opacity Min
* @text 召唤战场属性最低不透明度
* @type number
* @min 0
* @max 255
* @default 125
* @desc 战场属性入场时，精灵不透明度从该值逐渐增加至255，退场时，从255逐渐减少至该值
*
* @help
* 全场状态-战场属性
* 若使用了YEP战斗序列，请放在战斗序列的下面
* 若使用了YEP状态核心，请放在状态核心的下面
* 若本插件版本在1.10以上，不可以将状态对象写入存档
*
* 请优先配置插件参数。
* 
* 状态标签
* <Global State Type: type>
* 全场状态类型，type可取值为
* all：影响全场敌我目标
* party：影响全体我方
* troop：影响全体敌方
* custom：自定义影响范围
* element：影响战场属性，属性将影响技能物品的使用及效果
*
* <Global State Area Custom>
* // JavaScript code
* targets.push($gameParty.leader());
* targets.push($gameTroop.members()[0]);
* </Global State Area Custom>
* 自定义全场状态影响范围，targets数组中的目标会受影响。
* 变量state表示当前配置的状态。
* 当状态类型为custom时才有效。
*
* <State Element: x>
* 指定战场属性，配置属性列表中一个属性的id值。
* 对任意全场状态均有效，即使类型不是element。
*
* <Global State Count Max: x>
* 指定全场状态的最大叠加层数，x为整数
* 如果配置为0，表示层数无限制。
* 如果不配置，以插件参数为准。
*
* <Global Next State: x>
* 对多层全场状态生效，指定该状态的下级状态为x，x为状态id
* 若一个全场状态有trait效果且有n层，则总trait效果为：
* 当前状态 + (n -1)个下级状态的所有trait对象的叠加
* 若不配置，下级状态就是当前状态。
*
* 关于【战场属性列表】的配置方法
* 该参数各分项是战场属性的列表项，各分项配置方法如下：
* 元素名：管理用，默认不参与其他功能。
* 元素标签：字符串，建议以英文+下划线形式命名，不可以有空格。
* 我们假设某个元素的标签名是FIRE，则有
* （1）战斗中，表达式【CP.FIRE】表示该元素的总层数，此总层数已经过战场
* 属性层数变换。
* （2）战场属性变换函数中，elementArr.FIRE表示该元素的默认层数。
* 元素图：战斗中有改元素时展示的图片素材
* 原点X，原点Y：元素图的锚点
* 元素坐标X，元素坐标Y：元素图的显示坐标。
* 注意：战场属性的id就是该项在列表的位置，从1起。
* 即第一项战场属性id=1，第二项id=2，以此类推。
*
* 关于【全场状态的层数】
* 全场状态允许叠层，可以通过额外代码使叠层产生效果。
* 同时，战场属性的层数与对应状态的层数相关。
* 默认情况下，一个战场属性的总层数是所有相关全场状态的层数和。
* 如果你想让各个战场属性在层数上相互影响，请配置【战场属性层数变换
* 函数】。
* 该函数有两个参数，分述如下：
* elementId：当前需要求解层数的战场属性id
* elementArr：对象，保存所有战场属性的默认层数
* elementArr.FIRE表示symbol为FIRE的战场属性的默认层数。
* 返回值为战场属性elementId的最终层数
*
* 全场状态额外代码
* <Custom Add Global State Eval>
* //JavaScript code
* $gameParty.battleMembers().forEach(function(actor){
*   if(actor.hpRate() < 0.5)
*       actor.addState(actor.deathStateId());
* });
* </Custom Add Global State Eval>
* 全场状态添加时执行的额外代码
* 
* <Custom Remove Global State Eval>
* //JavaScript code
* $gameParty.battleMembers().forEach(function(actor){
*   actor.gainHp(-Math.round(actor.mhp / 2));
*   actor.gainMp(-Math.round(actor.mmp / 2));
*   actor.startDamagePopup();
* });
* </Custom Remove Global State Eval>
* 全场状态解除时执行的额外代码
* 
* <Custom Update Global State Eval>
* //JavaScript code
* $gameParty.battleMembers().forEach(function(actor){
*   actor.gainHp(-Math.round(actor.mhp / 10));
*   actor.startDamagePopup();
* });
* </Custom Update Global State Eval>
* 全场状态存在时每回合都会执行的额外代码
*
* <Custom EndAction Global State Eval>
* //JavaScript code
* if(subject.isActor())
*   subject.gainExp(2);
* </Custom EndAction Global State Eval>
* 全场状态存在时每次行动后都会执行的额外代码
* 注意：只要这个全场状态存在，战斗中任何行动结束时都会执行代码。
* 如果你只需要被影响的目标执行内容，请配置YEP状态核心。
*
* 在上述四个额外代码中有以下共用变量
* subject表示当前行动的发起方，只在EndAction中使用
* this指向BattleManager对象本身
* 
* 物品/技能标签 
* <Add Global State: x>
* 使用该物品/技能时添加全场状态x
* <Add Global Count: count>
* 上文中指定添加的全场状态x叠加count层
* 
* <Remove Global State: x>
* 使用该物品/技能时解除全场状态x
* <Remove Global Count: count>
* 上文中指定移除的全场状态移除count层
* <Remove Global State Completely>
* 完全移除上文指定的全场状态
* 注意：有以上五个标签的物品只能在战斗中使用
* 
* <Battle Element: x, x, x>
* 物品/技能需要的战场属性数值，可多个。
* <Battle Element: 1> 技能物品需要战场属性1
* <Battle Element: 2, 3, 5> 技能物品需要战场属性2，属性3，属性5，当三种属
* 性全部存在时满足条件。
* 满足条件时指定的技能物品才能被使用。
*
* 若使用了YEP战斗序列插件，则可以使用下面的战斗序列指令：
* Add Global State: x, [count] 添加全场状态x count层，count可选，省略为1
* Remove Global State: x, [count] 解除全场状态x count层，count可选，省略为1
* 在Remove指令中count可取字符串all，表示完全移除状态
* 例子：
* Add Global State: 10, 2 添加全场状态10 2层
* Remove Global State: 10 解除全场状态10 1层
*
* 插件指令（只能在战斗中使用）
* GlobalState add x count 添加全场状态x count层
* GlobalState remove x 移除全场状态x count层
* 如果count参数省略，表示变更1层
* 在remove指令中count可取字符串all，表示完全移除状态
* 例子：
* GlobalState add 10 3 添加全场状态10 3层
* GlobalState remove 10 解除全场状态10 1层
* GlobalState remove 10 all 完全解除全场状态10
*
* 此外，亦可用脚本添加或移除全场状态
* BattleManager.addGlobalState(stateId, count); 添加全场状态若干层
* BattleManager.removeGlobalState(stateId, count); 移除全场状态若干层
* BattleManager.removeGlobalStateCompletely(stateId) 完全移除一个全场状态
* 以上三个函数返回布尔值，表示是否执行成功
* 注意：以上三个函数不执行战场属性图标的刷新
*
* 刷新属性图标，使用下面的函数：
* BattleManager.requestElementSpritesUpdate(elementId)
* 刷新指定战场属性的图标的显示状态
* BattleManager.requestElementSpritesUpdateAll()
* 刷新所有战场属性的图标的显示状态
* BattleManager.addMovableElement(elenentId, moveType, success)
* 召唤一个移动的属性图标
* elementId：指定战场属性id
* moveType：移动类型，只有两个值可选
* （1）Sprite_MovableGlobalElement.MOVE_TYPE_FORWARD：添加属性时
* （2）Sprite_MovableGlobalElement.MOVE_TYPE_BACK：移除属性时
* success：布尔值，状态是否变更成功，true时才会正常出现移动图标
* 当这个移动图标到位时，会自动刷新一次战场属性图标状态
*
* 战斗开始时，可指定立即添加的全场状态
* 以下标签可添加至全场状态的备注中
* <Global State Auto Add Condition: Always>
* 无条件使该状态战斗开始时添加
* <Global State Auto Add Condition: Switch x, x, x>
* 若干变量为on时，满足条件
* <Global State Auto Add Condition: Variable x, Above y>
* 变量x值大于y时满足条件
* <Global State Auto Add Condition: Variable x, Below y>
* 变量x值小于y时满足条件
* <Global State Auto Add Condition: Variable x, Range y1, y2>
* 变量x值在闭区间[y1,y2]时满足条件，此项必须满足y1<y2
* <Global State Auto Add Condition Eval>
* //JS代码
* condition = $gameParty.gold() > 10000;
* </Global State Auto Add Condition Eval>
* 变量condition=true时满足条件
* 以上所有内容可以组合配置，所有条件满足判定为满足条件
* 满足条件时该全场状态在战斗开始时即添加
* Always除外，带有Always条件的全场状态忽略其他内容，判定为满足条件
* 默认情况下，战斗开始立即添加的状态只有一层，若需要添加多层，有以下
* 标签：
* 下面的标签添加至全场状态的备注中
* <Global State Auto Add Count Eval>
* //JS代码
* count = Math.min(5, Math.round($gameParty.gold() / 1000));
* if(count < 1)
*   count = 1;
* </Global State Auto Add Count Eval>
* 当该状态满足自动添加条件时配置本标签才有效
* this表示BattleManager对象，最终count>=1才满足条件
*
* 其他JavaScript函数
* BattleManager.isGlobalStateAffected(stateId) 战场是否存在指定状态
* BattleManager.hasGlobalElement(elementId) 战场是否存在指定属性
* BattleManager.requestGlobalStatesChange() 请求战场刷新所有已有状态
* 该函数在全场状态添加移除时将会主动调用
* BattleManager.refreshGlobalStateMembers() 刷新所有全场状态的影响目标
* 该函数在上一函数内以及战斗者的refresh中主动调用
*
* 补充：技能/物品的制作方法
* 1. 标签法：用标签定义添加/移除的状态和层数
* 2. 序列法：使用YEP战斗序列指令执行操作
* 3. 公共事件法：使用公共事件调用插件指令实现效果
* 方法1只能做单状态变化，执行效果在技能/道具动画之前
* 方法2和3相对自由，可以多状态变化，3一般在动画执行后
* 
* 更新日志 
* v1.00
* 插件完成
*
* v1.01
* 修复非战场属性型状态在战斗者上的显示偏差
*
* v1.02
* 修复需战场属性才可使用的战斗物品在没有战场属性时不显示的问题
*
* v1.03
* 追加状态添加、解除、回合更新时执行额外代码
*
* v1.04
* 修复游戏在没有进过战斗的情况下进入技能界面报错的问题
*
* v1.05
* 修复全场状态在战斗结束后依然生效的BUG
*
* v1.06
* 修复全场状态持续回合数显示错误的问题
*
* v1.07
* 添加技能添加移除全场状态的标签
* 支持通过YEP战斗序列指令调整全场状态
*
* v1.08
* 添加战斗开始自动添加全场状态的功能
* 全场状态支持在行动结束时执行额外代码
*
* v1.09
* 解决YEP-ATB战斗模式下，使用EndAction额外代码调用公共事件不会立即执行
* 的问题
*
* v1.10
* 优化算法性能，使状态运算不再是每次调用
* 将所有代码字符串转化为函数
*
* v1.11
* 取消战场属性的element类型限制
* 添加全场状态的层数与战场属性的层数定义
* 添加战场属性层数的自定义表示
* 添加战场属性的图标UI配置
*
* v1.12
* 增加全场状态最大层数的默认值
* 修复标签型技能需要设置目标的问题
*
* v1.13
* 修复不指定自动添加层数时无法在战斗开始时添加状态的问题
* 如果不指定自动添加层数，默认为1
*/
/*~struct~elementData:
 * @param name
 * @text 元素名
 *
 * @param symbol
 * @text 元素标签
 * @desc 标签名，JS调用使用，如果标签名为A，则elementObject.A表示该元素的层数
 *
 * @param image
 * @text 元素图
 * @type file
 * @dir img/system
 * @desc 战斗中显示的元素精灵图
 *
 * @param anchorX
 * @text 原点X
 * @type number
 * @decimals 2
 * @min 0
 * @max 1
 * @default 0.50
 *
 * @param anchorY
 * @text 原点Y
 * @type number
 * @decimals 2
 * @min 0
 * @max 1
 * @default 0.50
 *
 * @param posX
 * @text 元素坐标X
 * @type note
 * @default "return elementId * 60;"
 * @desc 函数，this对象为Scene_Battle，elementId为元素序号，从1起。
 *
 * @param posY
 * @text 元素坐标Y
 * @type note
 * @default "return 0;"
 * @desc 函数，this对象为Scene_Battle，elementId为元素序号，从1起。
 *
 * @param countColor
 * @text 元素层数文字颜色
 * @default #FFFF40
 *
 * @param countX
 * @text 元素层数文字X
 * @type note
 * @default "return 0;"
 *
 * @param countY
 * @text 元素层数文字Y
 * @type note
 * @default "return 0;"
 */
/*~struct~elementText:
 * @param text
 * @text 提示文字
 * @default %1+
 * @desc %1表示当前元素的叠加层数
 *
 * @param font
 * @text 文字字体
 * @default GameFont
 *
 * @param size
 * @text 文字大小
 * @type number
 * @default 18
 */

var Imported = Imported || {};
Imported.CP_GlobalState = true;

var CP = CP || {};
CP.GlobalManager = CP.GlobalManager || {};
CP.GlobalManager.Param = PluginManager.parameters("CP_GlobalState");
CP.GlobalManager.DEFAULT_GLOBAL_STATE_COUNT_MAX = Number(CP.GlobalManager.Param["Default Global State Count Max"]) || 0;
CP.GlobalManager.GLOBAL_ELEMENT_LIST = JSON.parse(CP.GlobalManager.Param["Element List"]).map(function(itemStr, index){
	var item = JSON.parse(itemStr);
	item.id = index + 1;
	item.name = item.name.trim();
	item.symbol = item.symbol.trim();
	item.image = ImageManager.loadSystem(item.image);
	item.anchorX = Number(item.anchorX) || 0;
	item.anchorY = Number(item.anchorY) || 0;
	item.posX = new Function("elementId", JSON.parse(item.posX));
	item.posY = new Function("elementId", JSON.parse(item.posY));
	item.countColor = item.countColor.trim();
	item.countX = new Function("elementId", JSON.parse(item.countX));
	item.countY = new Function("elementId", JSON.parse(item.countY));
	return item;
});

CP.GlobalManager.GLOBAL_ELEMENT_TOTAL_COUNT_FUNCTION = new Function("elementId", "elementArr"
	, JSON.parse(CP.GlobalManager.Param["Element Total Count Function"]));

CP.GlobalManager.GLOBAL_ELEMENT_TEXT_DATA = JSON.parse(CP.GlobalManager.Param["Element Count Text"]);
CP.GlobalManager.GLOBAL_ELEMENT_TEXT_DATA.text = CP.GlobalManager.GLOBAL_ELEMENT_TEXT_DATA.text.trim();
CP.GlobalManager.GLOBAL_ELEMENT_TEXT_DATA.size = Number(CP.GlobalManager.GLOBAL_ELEMENT_TEXT_DATA.size) || 18;

CP.GlobalManager.GLOBAL_ELEMENT_HOME_POSITION = {
	x: new Function("elementId", JSON.parse(CP.GlobalManager.Param["Element Home X"])),
	y: new Function("elementId", JSON.parse(CP.GlobalManager.Param["Element Home Y"]))
};

CP.GlobalManager.GLOBAL_ELEMENT_MOVE_TIME = Number(CP.GlobalManager.Param["Element Move Time"]) || 0;
CP.GlobalManager.GLOBAL_ELEMENT_OPACITY_MIN = Number(CP.GlobalManager.Param["Element Opacity Min"]) || 0;

//全场状态类型
CP.GlobalManager.GLOBAL_TYPE_NONE = 0;//非全场状态
CP.GlobalManager.GLOBAL_TYPE_ALL = 1; //全场状态，影响所有人
CP.GlobalManager.GLOBAL_TYPE_PARTY = 2; //全场状态，影响我方
CP.GlobalManager.GLOBAL_TYPE_TROOP = 3; //全场状态，影响敌方
CP.GlobalManager.GLOBAL_TYPE_CUSTOM = 4; //全场状态，自定义影响范围
CP.GlobalManager.GLOBAL_TYPE_ELEMENT = 5 //全场状态，属性祭符

//额外代码执行时机
CP.GlobalManager.GLOBAL_EVAL_ADD = 1;
CP.GlobalManager.GLOBAL_EVAL_REMOVE = 2;
CP.GlobalManager.GLOBAL_EVAL_UPDATE = 3;
CP.GlobalManager.GLOBAL_EVAL_END_ACTION = 4;

//数据库注释读取
CP.GlobalManager._loaded = false;
CP.GlobalManager.DATABASE_LOADED = DataManager.isDatabaseLoaded;
DataManager.isDatabaseLoaded = function(){
	if(!CP.GlobalManager.DATABASE_LOADED.call(this))
		return false;

	if(!CP.GlobalManager._loaded){
		CP.GlobalManager.loadGlobalStates();
		CP.GlobalManager.loadGlobalStatesCustomArea();
		CP.GlobalManager.loadGlobalStatesCustomEval();
		CP.GlobalManager.loadGlobalStateAutoAdd();

		CP.GlobalManager.loadItemGlobalStatesAction($dataSkills);
		CP.GlobalManager.loadItemGlobalStatesAction($dataItems);	

		CP.GlobalManager.loadElementCondition($dataSkills);
		CP.GlobalManager.loadElementCondition($dataItems);

		CP.GlobalManager._loaded = true;
	}

	return true;
};

CP.GlobalManager.loadGlobalStates = function(){
	for(var i = 1; i < $dataStates.length; i++){
		var state = $dataStates[i];
		state.globalType = this.GLOBAL_TYPE_NONE;
		state.globalElement = 0;
		state.globalStateCountMax = 0; //状态层数最大值
		state.globalNextState = 0; //下级状态

		if(state.meta["Global State Type"]){
			var type = state.meta["Global State Type"].trim().toUpperCase();
			switch(type){
				case "ALL":
					state.globalType = this.GLOBAL_TYPE_ALL;
					break;
				case "PARTY":
					state.globalType = this.GLOBAL_TYPE_PARTY;
					break;
				case "TROOP":
					state.globalType = this.GLOBAL_TYPE_TROOP;
					break;
				case "CUSTOM":
					state.globalType = this.GLOBAL_TYPE_CUSTOM;
					break;
				case "ELEMENT":
					state.globalType = this.GLOBAL_TYPE_ELEMENT;
			}
		}

		if(state.globalType !== this.GLOBAL_TYPE_NONE){
			state.globalStateCountMax = this.DEFAULT_GLOBAL_STATE_COUNT_MAX; //0表示无限叠层
			state.globalNextState = i; //默认下级状态是自身
			if(state.meta["Global State Count Max"])
				state.globalStateCountMax = Number(state.meta["Global State Count Max"]) || 0;
			if(state.meta["Global Next State"])
				state.globalNextState = Number(state.meta["Global Next State"]) || i;
			if(state.meta["State Element"]){
				var el = Number(state.meta["State Element"]) || 0;
				state.globalElement = el > 0 ? el : 0;
			}
		}
	}
};

CP.GlobalManager.loadGlobalStatesCustomArea = function(){
	for(var i = 1; i < $dataStates.length; i++){
		var state = $dataStates[i];
		state.globalCustomAreaEval = null;
		if(state.globalType !== this.GLOBAL_TYPE_CUSTOM)
			continue;

		if(state.meta["Global State Area Custom"]){
			var reg = /<Global State Area Custom>([\S\s]*)<\/Global State Area Custom>/;
			reg.exec(state.note);

			state.globalCustomAreaEval = new Function("var targets = [];\n" + RegExp.$1 + "\nreturn targets;");
		}
	}
};

CP.GlobalManager.loadGlobalStatesCustomEval = function(){
	for(var i = 1; i < $dataStates.length; i++){
		var state = $dataStates[i];
		state.globalCustomEval = {};

		if(state.meta["Custom Add Global State Eval"]){
			var reg = /<Custom Add Global State Eval>([\s\S]*)<\/Custom Add Global State Eval>/;
			reg.exec(state.note);
			state.globalCustomEval.add = new Function("subject", RegExp.$1);
		}

		if(state.meta["Custom Remove Global State Eval"]){
			var reg = /<Custom Remove Global State Eval>([\s\S]*)<\/Custom Remove Global State Eval>/;
			reg.exec(state.note);
			state.globalCustomEval.remove = new Function("subject", RegExp.$1);
		}

		if(state.meta["Custom Update Global State Eval"]){
			var reg = /<Custom Update Global State Eval>([\s\S]*)<\/Custom Update Global State Eval>/;
			reg.exec(state.note);
			state.globalCustomEval.update = new Function("subject", RegExp.$1);
		}

		if(state.meta["Custom EndAction Global State Eval"]){
			var reg = /<Custom EndAction Global State Eval>([\s\S]*)<\/Custom EndAction Global State Eval>/;
			reg.exec(state.note);
			state.globalCustomEval.endAction = new Function("subject", RegExp.$1);
		}
	}
};

CP.GlobalManager.loadGlobalStateAutoAdd = function(){
	for(var i = 1; i < $dataStates.length; i++){
		var state = $dataStates[i];
		state.globalAutoAddData = {};
		state.globalAutoAddData.always = false;
		this.loadGlobalStateAutoAddData(state);
		this.loadGlobalStateAutoAddEvalCondition(state);
		this.loadGlobalStateAutoAddCount(state);
	}
};

CP.GlobalManager.loadGlobalStateAutoAddData = function(state){
	var reg1 = /<Global State Auto Add Condition: Switch ([^<>]+)>/;
	var reg2 = /<Global State Auto Add Condition: Variable (\d+), Above ([+-]?\d+(\.\d+)*)>/;
	var reg3 = /<Global State Auto Add Condition: Variable (\d+), Below ([+-]?\d+(\.\d+)*)>/;
	var reg4 = /<Global State Auto Add Condition: Variable (\d+), Range ([+-]?\d+(\.\d+)*), ([+-]?\d+(\.\d+)*)>/;
	var reg5 = /<Global State Auto Add Condition: Always>/;

	var notes = state.note.split("\n");
	state.globalAutoAddData.switches = [];
	state.globalAutoAddData.variables = [];

	for(var i = 0; i < notes.length; i++){
		var note = notes[i];
		if(reg1.exec(note)){
			//开关
			var switches = RegExp.$1.split(",").map(function(n){
				return Number(n) || 0;
			});
			for(var k = 0; k < switches.length; k++){
				var sn = switches[k];
				if(sn > 0 && !state.globalAutoAddData.switches.contains(sn))
					state.globalAutoAddData.switches.push(sn);
			}
		}else if(reg2.exec(note)){
			//变量 大于min
			var v = Number(RegExp.$1) || 0;
			var value = Number(RegExp.$2) || 0;
			state.globalAutoAddData.variables.push(this.getVariableConditionData(v, value, null))
		}else if(reg3.exec(note)){
			//变量 小于 max
			var v = Number(RegExp.$1) || 0;
			var value = Number(RegExp.$2) || 0;
			state.globalAutoAddData.variables.push(this.getVariableConditionData(v, null, value));
		}else if(reg4.exec(note)){
			var v = Number(RegExp.$1) || 0;
			var value1 = Number(RegExp.$2) || 0;
			var value2 = Number(RegExp.$4) || 0;
			state.globalAutoAddData.variables.push(this.getVariableConditionData(v, value1, value2));
		}else if(reg5.exec(note))
			state.globalAutoAddData.always = true;
	}
};

CP.GlobalManager.getVariableConditionData = function(variableId, min, max){
	return {variableId: variableId, min: min, max: max};
}

CP.GlobalManager.loadGlobalStateAutoAddEvalCondition = function(state){
	var reg = /<Global State Auto Add Condition Eval>([\s\S]*?)<\/Global State Auto Add Condition Eval>/;
	state.globalAutoAddData.eval = null;
	if(reg.exec(state.note)){
		state.globalAutoAddData.eval = new Function("var condition = false;\n" + RegExp.$1.trim() 
			+ "\nreturn condition;");
	}
};

CP.GlobalManager.loadGlobalStateAutoAddCount = function(state){
	var reg = /<Global State Auto Add Count Eval>([\s\S]*?)<\/Global State Auto Add Count Eval>/;
	state.globalAutoAddData.count = null;
	if(reg.exec(state.note)){
		state.globalAutoAddData.count = new Function("var count = 0;\n" + RegExp.$1.trim() + "\nreturn count;");
	}
};

CP.GlobalManager.loadItemGlobalStatesAction = function(array){
	for(var i = 1; i < array.length; i++){
		var item = array[i];
		item.addGlobalStateId = 0;
		item.removeGlobalStateId = 0;
		item.addGlobalCount = 0;
		item.removeGlobalCount = 0;
		item.removeGlobalCompletely = false; //完全解除

		if(item.meta["Add Global State"]){
			var addId = Number(item.meta["Add Global State"]) || 0;
			item.addGlobalStateId = addId;
		}
		if(item.meta["Remove Global State"]){
			var removeId = Number(item.meta["Remove Global State"]) || 0;
			item.removeGlobalStateId = removeId;
		}
		if(item.addGlobalStateId > 0){
			if(item.meta["Add Global Count"]){
				var addCount = Number(item.meta["Add Global Count"]) || 1;
				item.addGlobalCount = addCount > 0 ? addCount : 1;
			}else
				item.addGlobalCount = 1;
		}
		if(item.removeGlobalStateId > 0){
			if(item.meta["Remove Global State Completely"])
				item.removeGlobalCompletely = true;
			else if(item.meta["Remove Global Count"]){
				var removeCount = Number(item.meta["Remove Global Count"]) || 1;
				item.removeGlobalCount = removeCount > 0 ? removeCount : 1;
			}else
				item.removeGlobalCount = 1;
		}
	}
};

CP.GlobalManager.loadElementCondition = function(array){
	for(var i = 1; i < array.length; i++){
		var item = array[i];
		item.globalElements = null;

		if(item.meta["Battle Element"]){
			item.globalElements = [];
			var result = item.meta["Battle Element"].trim().split(",");
			result.forEach(function(t){
				var n = Number(t) || 0;
				if(n > 0)
					item.globalElements.push(n);
			});
		}
	}
};

//得到指定id的元素对象
CP.GlobalManager.getGlobalElementById = function(elementId){
	var element = this.GLOBAL_ELEMENT_LIST[elementId - 1];
	return !!element ? element : null;
};

//状态是否为全场状态
CP.GlobalManager.isGlobalState = function(stateId){
	var state = $dataStates[stateId];
	if(!state)
		return false;

	return state.globalType > this.GLOBAL_TYPE_NONE;
};

//全场状态的战场属性
CP.GlobalManager.getGlobalElement = function(stateId){
	if(!this.isGlobalState(stateId))
		return 0;

	return $dataStates[stateId].globalElement;
};

CP.GlobalManager.membersForGlobalStateAffected = function(stateId){
	if(!this.isGlobalState(stateId))
		return [];

	var state = $dataStates[stateId];
	switch(state.globalType){
		case this.GLOBAL_TYPE_PARTY:
			return $gameParty.members();
		case this.GLOBAL_TYPE_TROOP:
			return $gameTroop.members();
		case this.GLOBAL_TYPE_ALL:
			return $gameParty.members().concat($gameTroop.members());
		case this.GLOBAL_TYPE_CUSTOM:
			return this.customGlobalStateArea(state);
	}

	return [];
};

CP.GlobalManager.customGlobalStateArea = function(state){
	try{
		return state.globalCustomAreaEval();
	}catch(err){
		console.error(err);
		return [];
	}
};

//---------------------------
//          BattleManager
//---------------------------
CP.GlobalManager.SETUP_BATTLE = BattleManager.setup;
BattleManager.setup = function(troopId, canEscape, canLose){
	this._elementSpriteNeedUpdate = {};
	this._movableElements = []; //移动属性标签请求
    CP.GlobalManager.SETUP_BATTLE.call(this, troopId, canEscape, canLose);

    this.initGlobalStateMembers();
    this.initGlobalStatesAndElements();
    this.requestElementSpritesUpdateAll();
};

//初始化状态数组
BattleManager.initGlobalStatesAndElements = function(){
	if(!this._globalStates || (this._globalStates && this._globalStates.length > 0))
		this._globalStates = [];
	this.requestGlobalStatesChange();
};

BattleManager.initGlobalElement = function(){
	this._globalElements = null;
};

//战斗中元素精灵的刷新请求
BattleManager.requestElementSpritesUpdate = function(elementId){
	if(elementId > 0)
		this._elementSpriteNeedUpdate[elementId] = true;
};

BattleManager.resetElementSpritesUpdate = function(elementId){
	if(elementId > 0)
		this._elementSpriteNeedUpdate[elementId] = false;
};

BattleManager.isElementSpriteUpdateRequested = function(elementId){
	return !!this._elementSpriteNeedUpdate[elementId];
};

//所有战场元素精灵请求刷新
BattleManager.requestElementSpritesUpdateAll = function(){
	CP.GlobalManager.GLOBAL_ELEMENT_LIST.forEach((element) => {
		if(!!element)
			this.requestElementSpritesUpdate(element.id);
	});
};

//添加移动请求
BattleManager.addMovableElement = function(elementId, moveType, success){
	if(elementId > 0 && success)
		this._movableElements.push({elementId: elementId, moveType: moveType});
};

//是否有移动请求
BattleManager.isMovableElememtNeeded = function(){
	return this._movableElements.length > 0;
};

//清空移动请求
BattleManager.resetMovableElements = function(){
	this._movableElements.splice(0, this._movableElements.length);
};

//所有移动请求，格式{elementIId, moveType}
BattleManager.allMovableElements = function(){
	return this._movableElements;
};

//初始化状态影响目标
BattleManager.initGlobalStateMembers = function(){
	this._globalStateMembers = {};
};

//刷新目标，globalState结构：{id, turn}
BattleManager.refreshGlobalStateMembers = function(){
	this.initGlobalStateMembers();
	this.globalStateData().forEach(function(globalState){
		this._globalStateMembers[globalState.id] = CP.GlobalManager.membersForGlobalStateAffected(globalState.id);
	}, this);
};

//指定状态的影响目标
BattleManager.globalStateMembers = function(stateId){
	if(!this._globalStateMembers)
		return [];
	if(!this._globalStateMembers[stateId])
		return [];
	return this._globalStateMembers[stateId];
};

//是否存在全场状态
BattleManager.isGlobalStateAffected = function(stateId){
	return this.globalStateIndex(stateId) >= 0;
};

//全场状态在状态数组的索引
BattleManager.globalStateIndex = function(stateId){
	if(!BattleManager._globalStates)
		return -1;

	for(var i = 0; i < this._globalStates.length; i++){
		var state = this._globalStates[i];
		if(state.id === stateId)
			return i;
	}

	return -1;
};

BattleManager.requestGlobalStatesChange = function(){
	var members = $gameParty.members().concat($gameTroop.members());
	members.forEach(function(battler){
		battler.requestGlobalStatesChange();
	});
	this.initGlobalElement();
	this.refreshGlobalStateMembers();
};

//添加全场状态
BattleManager.addGlobalState = function(stateId, count){
	count = count || 1;
	if(!CP.GlobalManager.isGlobalState(stateId))
		return false;

	if(!this.isGlobalStateAffected(stateId))
		this.addNewGlobalState(stateId, count);
	else
		this.gainGlobalStateCount(stateId, count);

	this.resetGlobalStateTurns(stateId);
	this.execGlobalStateCustomEval(stateId, CP.GlobalManager.GLOBAL_EVAL_ADD);

	return true;
};

//添加新的全场状态
BattleManager.addNewGlobalState = function(stateId, count){
	var state = $dataStates[stateId];
	var turn = state.minTurns;

	var globalState = {};
	globalState.id = stateId;
	globalState.count = 0; //叠层数定义 这里是0，层数叠加到后面
	globalState.turns = state.autoRemovalTiming > 0 ? state.minTurns : -1;

	this._globalStates.push(globalState);
	this.gainGlobalStateCount(stateId, count);
	this.requestGlobalStatesChange();
};

//全场状态层数变更
BattleManager.gainGlobalStateCount = function(stateId, count){
	var state = $dataStates[stateId];
	var index = this.globalStateIndex(stateId);
	var max = state.globalStateCountMax;
	if(index >= 0){
		this._globalStates[index].count += Math.floor(count);
		if(max > 0 && this._globalStates[index].count > max)
			this._globalStates[index].count = Math.floor(max);
	}
};

//重置全场状态回合数
BattleManager.resetGlobalStateTurns = function(stateId){
	var state = $dataStates[stateId];

	if(state.autoRemovalTiming > 0){
		var index = this.globalStateIndex(stateId);
		var floatTurn = Math.random() * (state.maxTurns - state.minTurns);
		var turn = state.minTurns + Math.round(floatTurn);

		this._globalStates[index].turns = turn;
	}
};

//移除全场状态
BattleManager.removeGlobalState = function(stateId, count){
	count = count || 1;
	if(count < 0)
		count = 1;

	if(!CP.GlobalManager.isGlobalState(stateId))
		return false;

	if(!this.isGlobalStateAffected(stateId))
		return false;

	var index = this.globalStateIndex(stateId);
	this._globalStates[index].count -= count;
	if(this._globalStates[index].count <= 0)
		this._globalStates.splice(index, 1);
	this.requestGlobalStatesChange();

	this.execGlobalStateCustomEval(stateId, CP.GlobalManager.GLOBAL_EVAL_REMOVE);

	return true;
};

//完全移除一个全场状态
BattleManager.removeGlobalStateCompletely = function(stateId){
	return this.removeGlobalState(stateId, this.globalStateCount(stateId));
};

BattleManager.globalStateCount = function(stateId){
	if(!CP.GlobalManager.isGlobalState(stateId))
		return 0;
	var index = this.globalStateIndex(stateId);
	if(index >= 0)
		return this._globalStates[index].count;
	else
		return 0;
};

BattleManager.globalStateTurn = function(stateId){
	if(!CP.GlobalManager.isGlobalState(stateId))
		return -1;

	var index = this.globalStateIndex(stateId);
	if(index >= 0)
		return this._globalStates[index].turns;
	else
		return -1;
};

CP.GlobalManager.UPDATE_TURN_END = BattleManager.updateTurnEnd;
BattleManager.updateTurnEnd = function() {
    CP.GlobalManager.UPDATE_TURN_END.call(this);

    this.updateGlobalStateTurns();
};

//更新全场状态回合数
BattleManager.updateGlobalStateTurns = function(){
	for(var i = 0; i < this._globalStates.length; i++){
		var state = this._globalStates[i];
		if(state.turns === -1)
			continue;

		state.turns--;
		if(state.turns <= 0)
			this.removeGlobalState(state.id, 1);
		else
			this.execGlobalStateCustomEval(state.id, CP.GlobalManager.GLOBAL_EVAL_UPDATE);
	}
};

BattleManager.globalStateData = function(){
	if(!this._globalStates)
		return [];
	else
		return this._globalStates;
}

BattleManager.globalStates = function(){
	var states = [];
	if(!this._globalStates)
		return states;

	for(var i = 0; i < this._globalStates.length; i++){
		var st = this._globalStates[i];
		states.push($dataStates[st.id]);
	}

	return states;
};

BattleManager.globalElements = function(){
	if(!this._globalElements)
		this._globalElements = this.globalElementsData();
	return this._globalElements;
};

BattleManager.globalElementsData = function(){
	var states = this.globalStates();
	var elements = [];

	states.forEach(function(state){
		if(state.globalElement > 0)
			elements.push(state.globalElement);
	});

	return elements;
};

BattleManager.hasGlobalElement = function(elementId){
	return this.globalElements().contains(elementId);
};

BattleManager.getGlobalStatesByElement = function(elementId){
	var globalStates = this.globalStates();
	var res = [];
	for(var i = 0; i < globalStates.length; i++){
		var st = globalStates[i];
		if(st.globalElement === elementId)
			res.push(st);
	}
	return res;
};

//战场上某个元素的总和【无转换规则】
BattleManager.globalElementCount = function(elementId){
	if(!this.hasGlobalElement(elementId))
		return 0;

	var globalStates = this.getGlobalStatesByElement(elementId);
	return globalStates.reduce((count, state) => count + this.globalStateCount(state.id), 0);
};

BattleManager.getGlobalElementCountObject = function(){
	var object = {};
	for(var i = 0; i < CP.GlobalManager.GLOBAL_ELEMENT_LIST.length; i++){
		var element = CP.GlobalManager.GLOBAL_ELEMENT_LIST[i];
		if(!!element)
			object[element.symbol] = this.globalElementCount(element.id);
	}
	return object;
};

//战场上某个元素的总和【有转换规则】
BattleManager.getGlobalElementCountTotal = function(elementId){
	var allElementsCount = this.getGlobalElementCountObject();
	return this.execGlobalElementTotal(elementId, allElementsCount);
};

//计算层数的规则函数
BattleManager.execGlobalElementTotal = function(elementId, elementObject){
	try{
		return CP.GlobalManager.GLOBAL_ELEMENT_TOTAL_COUNT_FUNCTION.call(this, elementId, elementObject);
	}catch(err){
		console.error(err);
		return this.globalElementCount(elementId);
	}
};

BattleManager.meetsGlobalElementConditions = function(item){
	var elements = this.globalElements();
	if(!item.globalElements || item.globalElements.length <= 0)
		return true;

	for(var i = 0; i < item.globalElements.length; i++){
		if(!this.hasGlobalElement(item.globalElements[i]))
			return false;
	}

	return true;
};

//执行额外代码
BattleManager.execGlobalStateCustomEval = function(stateId, timing){
	var fun = null;
	var state = $dataStates[stateId];

	if(!CP.GlobalManager.isGlobalState(stateId))
		return;

	switch(timing){
		case CP.GlobalManager.GLOBAL_EVAL_ADD:
			fun = state.globalCustomEval.add;
			break;
		case CP.GlobalManager.GLOBAL_EVAL_UPDATE:
			fun = state.globalCustomEval.update;
			break;
		case CP.GlobalManager.GLOBAL_EVAL_REMOVE:
			fun = state.globalCustomEval.remove;
			break;
		case CP.GlobalManager.GLOBAL_EVAL_END_ACTION:
			fun = state.globalCustomEval.endAction;
			break;
	}

	if(!fun)
		return;

	try{
		fun.call(this, this._subject);
	}catch(err){
		console.error(err);
	}
};

CP.GlobalManager.START_BATTLE = BattleManager.startBattle;
BattleManager.startBattle = function(){
	CP.GlobalManager.START_BATTLE.call(this);
	if($gameTroop.turnCount() === 0)
		this.addBattleStartGlobalStates();
};

BattleManager.addBattleStartGlobalStates = function(){
	this.allAutoAddGlobalStates().forEach(function(arr){
		this.addGlobalState(arr[0], arr[1]);
	}, this);
	this.requestElementSpritesUpdateAll();
};

BattleManager.allAutoAddGlobalStates = function(){
	var globalStates = [];
	for(var i = 0; i < $dataStates.length; i++){
		var state = $dataStates[i];
		if(this.meetsAutoGlobalState(state)){
			var count = this.getAutoGlobalStateCount(state);
			if(count > 0)
			globalStates.push([state.id, count]);
		}
	}
	return globalStates;
};

BattleManager.meetsAutoGlobalState = function(state){
	if(!state)
		return false;
	else if(!CP.GlobalManager.isGlobalState(state.id))
		return false;
	else if(state.globalAutoAddData.always) //Always 无条件满足
		return true;
	else if(state.globalAutoAddData.switches.length > 0 || state.globalAutoAddData.variables.length > 0
			|| state.globalAutoAddData.eval !== null){
		//当Always 开关 变量 eval至少有一项配置时，才开始严格检测
		//严格检测时，未配置项为true
		return this.meetsAutoGlobalStateSwitchConditions(state) 
			&& this.meetsAutoGlobalStateVariablesConditions(state)
			&& this.meetsAutoGlobalStateEvalConditions(state);

	}else //当所有项都未配置，不满足条件
		return false;
};

BattleManager.meetsAutoGlobalStateSwitchConditions = function(state){
	if(state.globalAutoAddData.switches.length <= 0)
		return true; //没有，跳过
	for(var i = 0; i < state.globalAutoAddData.switches.length; i++){
		if(!$gameSwitches.value(state.globalAutoAddData.switches[i]))
			return false;
	}
	return true;
};

BattleManager.meetsAutoGlobalStateVariablesConditions = function(state){
	if(state.globalAutoAddData.variables.length <= 0)
		return true; //没有，跳过
	for(var i = 0; i < state.globalAutoAddData.variables.length; i++){
		var varData = state.globalAutoAddData.variables[i];
		var value = $gameVariables.value(varData.variableId);
		if(varData.min !== null && varData.max === null){
			//存在最小值而不存在最大值，即V > X
			if(value > varData.min)
				continue;
			else
				return false;
		}else if(varData.min === null && varData.max !== null){
			//存在最大值而不存在最小值，即V < X
			if(value < varData.max)
				continue;
			else
				return false;
		}else if(varData.min !== null && varData.max !== null){
			//同时存在最大值和最小值，即X1 <= V <= X2，X1 <= X2
			if(varData.min > varData.max) //X1 > X2时，直接判定失败
				return false;
			else if(value > varData.max || value < varData.min)
				return false;
		}
	}
	return true;
};

BattleManager.meetsAutoGlobalStateEvalConditions = function(state){
	if(state.globalAutoAddData.eval === null)
		return true;
	
	try{
		return state.globalAutoAddData.eval.call(this);
	}catch(err){
		console.error(err);
		return false;
	}
};

BattleManager.getAutoGlobalStateCount = function(state){
	if(state.globalAutoAddData.count === null)
		return 1;
	try{
		return Math.round(state.globalAutoAddData.count.call(this));
	}catch(err){
		console.error(err);
		return 1;
	}
};

CP.GlobalManager.BATTLE_END_ACTION = BattleManager.endAction;
BattleManager.endAction = function(){
	this.executeGlobalStateEndActionEval();
	CP.GlobalManager.BATTLE_END_ACTION.call(this);
};

BattleManager.executeGlobalStateEndActionEval = function(){
	for(var i = 0; i < this._globalStates.length; i++){
		var state = this._globalStates[i];
		this.execGlobalStateCustomEval(state.id, CP.GlobalManager.GLOBAL_EVAL_END_ACTION);
	}
};

CP.GlobalManager.END_BATTLE = BattleManager.endBattle;
BattleManager.endBattle = function(result) {
	CP.GlobalManager.END_BATTLE.call(this, result);

	this.initGlobalStatesAndElements();
};

if(Imported.YEP_BattleEngineCore){

CP.GlobalManager.PROCESS_ACTION_SEQUENCE = BattleManager.processActionSequence;
BattleManager.processActionSequence = function(actionName, actionArgs){
	if(actionName.match(/ADD GLOBAL STATE/i))
		return this.actionAddGlobalState(actionArgs);
	if(actionName.match(/REMOVE GLOBAL STATE/i))
		return this.actionRemoveGlobalState(actionArgs);
	return CP.GlobalManager.PROCESS_ACTION_SEQUENCE.call(this, actionName, actionArgs);
};

BattleManager.actionAddGlobalState = function(actionArgs){
	var stateId = Number(actionArgs[0]) || 0;
	var count = Number(actionArgs[1]) || 1;
	if(stateId > 0 && count > 0){
		var success = this.addGlobalState(stateId, count);
		this.addMovableElement(CP.GlobalManager.getGlobalElement(stateId)
			, Sprite_MovableGlobalElement.MOVE_TYPE_FORWARD, success);
	}
	return true;
};

BattleManager.actionRemoveGlobalState = function(actionArgs){
	var stateId = Number(actionArgs[0]) || 0;
	var count = Number(actionArgs[1]) || 1;
	var success = false;

	if(stateId > 0){
		if(!!actionArgs[1] && actionArgs[1].trim().toUpperCase() == "ALL")
			success = this.removeGlobalStateCompletely(stateId);
		else if(count > 0)
			success = this.removeGlobalState(stateId, count);

		var elementId = CP.GlobalManager.getGlobalElement(stateId);
		this.requestElementSpritesUpdate(elementId);
		this.addMovableElement(elementId, Sprite_MovableGlobalElement.MOVE_TYPE_BACK, success);
	}
	return true;
};

}

CP.GlobalManager.GLOBAL_ELEMENT_LIST.forEach((element) =>{
	Object.defineProperty(CP, element.symbol, {
    	get: BattleManager.getGlobalElementCountTotal.bind(BattleManager, element.id),
    	configurable: true
	});
});

//---------------------------
//          Game_BattlerBase
//---------------------------
CP.GlobalManager.INIT_BATTLER_BASE_MEMBERS = Game_BattlerBase.prototype.initMembers;
Game_BattlerBase.prototype.initMembers = function(){
	this._globalStates = null;
	this._globalStateTraitObjects = null;
	CP.GlobalManager.INIT_BATTLER_BASE_MEMBERS.call(this);
};

Game_BattlerBase.prototype.requestGlobalStatesChange = function(){
	this._globalStates = null;
	this._globalStateTraitObjects = null;
};

Game_BattlerBase.prototype.isChangeGlobalStatesRequested = function(){
	return !this._globalStates || !this._globalStateTraitObjects;
};

Game_BattlerBase.prototype.meetsGlobalElementConditions = function(item){
	return BattleManager.meetsGlobalElementConditions(item);
};

CP.GlobalManager.MEETS_SKILL_CONDITIONS = Game_BattlerBase.prototype.meetsSkillConditions;
Game_BattlerBase.prototype.meetsSkillConditions = function(skill) {
    return CP.GlobalManager.MEETS_SKILL_CONDITIONS.call(this, skill) && this.meetsGlobalElementConditions(skill);
};

CP.GlobalManager.MEETS_ITEM_CONDITIONS = Game_BattlerBase.prototype.meetsItemConditions;
Game_BattlerBase.prototype.meetsItemConditions = function(item) {
    return CP.GlobalManager.MEETS_ITEM_CONDITIONS.call(this, item) && this.meetsGlobalElementConditions(item);
};

CP.GlobalManager.IS_BATTLER_STATE_AFFECTED = Game_BattlerBase.prototype.isStateAffected;
Game_BattlerBase.prototype.isStateAffected = function(stateId) {
    if(this.isGlobalStateAffected(stateId))
    	return true;

    return CP.GlobalManager.IS_BATTLER_STATE_AFFECTED.call(this, stateId);
};

Game_BattlerBase.prototype.isGlobalStateAffected = function(stateId){
	return BattleManager.isGlobalStateAffected(stateId) 
		&& BattleManager.globalStateMembers(stateId).contains(this); 
};

Game_BattlerBase.prototype.globalStateList = function(){
	var states = [];

	BattleManager.globalStateData().forEach(function(globalState){
		if(this.isGlobalStateAffected(globalState.id))
			states.push(globalState.id);
	}, this);

	return states;
};

Game_BattlerBase.prototype.globalStates = function(){
	if(this.isChangeGlobalStatesRequested())
		this._globalStates = this.globalStateList();
	return this._globalStates.map((stateId) => $dataStates[stateId]).filter((state) => !!state);
};

CP.GlobalManager.BATTLER_STATES = Game_BattlerBase.prototype.states;
Game_BattlerBase.prototype.states = function(){
	return CP.GlobalManager.BATTLER_STATES.call(this).concat(this.globalStates());
};

CP.GlobalManager.BATTLER_BASE_TRAIT_OBJECTS = Game_BattlerBase.prototype.traitObjects;
Game_BattlerBase.prototype.traitObjects = function(){
	return CP.GlobalManager.BATTLER_BASE_TRAIT_OBJECTS.call(this).concat(this.globalStateTraitObjects());
};

Game_BattlerBase.prototype.globalStateTraitObjects = function(){
	if(!this._globalStateTraitObjects)
		this._globalStateTraitObjects = this.globalStateTraitObjectList();
	return this._globalStateTraitObjects.map((stateId) => $dataStates[stateId]).filter((state) => !!state);
};

Game_BattlerBase.prototype.globalStateTraitObjectList = function(){
	var others = [];
	BattleManager.globalStateData().forEach(function(globalState){
		var curSt = $dataStates[globalState.id];
		if(this.isGlobalStateAffected(globalState.id)){
			var count = globalState.count - 1;
			for(var i = 0; i < count; i++)
				others.push(curSt.globalNextState);
		}
	}, this);
	return others;
};

CP.GlobalManager.BATTLER_BASE_REFRESH = Game_BattlerBase.prototype.refresh;
Game_BattlerBase.prototype.refresh = function(){
	this.requestGlobalStatesChange();
	if($gameParty.inBattle())
		BattleManager.refreshGlobalStateMembers();
	CP.GlobalManager.BATTLER_BASE_REFRESH.call(this);
};

if(Imported.YEP_BuffsStatesCore){
CP.GlobalManager.BATTLER_STATE_TURNS = Game_BattlerBase.prototype.stateTurns;
Game_BattlerBase.prototype.stateTurns = function(stateId){
    if(this.isGlobalStateAffected(stateId))
    	return BattleManager.globalStateTurn(stateId);
    return CP.GlobalManager.BATTLER_STATE_TURNS.call(this, stateId);
};
}

//---------------------------
//       Game_Battler
//---------------------------
CP.GlobalManager.BATTLER_PERFORM_ACTION = Game_Battler.prototype.performAction;
Game_Battler.prototype.performAction = function(action){
	CP.GlobalManager.BATTLER_PERFORM_ACTION.call(this, action);
	action.execGlobalStateAction();
};

//---------------------------
//          Game_Action
//---------------------------
Game_Action.prototype.execGlobalStateAction = function(){
	var addId = this.getAddGlobalStateId();
	var addCount = this.getAddGlobalStateCount();
	var removeId = this.getRemoveGlobalStateId();
	var removeCount = this.getRemoveGlobalStateCount();
	var isCompletely = this.isRemoveGlobalCompletely();
	var success = false;
	if(addId > 0 && addCount > 0){
		success = BattleManager.addGlobalState(addId, addCount);
		BattleManager.addMovableElement(CP.GlobalManager.getGlobalElement(addId)
			, Sprite_MovableGlobalElement.MOVE_TYPE_FORWARD, success);
	}
	else if(removeId > 0){
		var removeElement = CP.GlobalManager.getGlobalElement(removeId);
		if(isCompletely){
			success = BattleManager.removeGlobalStateCompletely(removeId);
			BattleManager.requestElementSpritesUpdate(removeElement);
			BattleManager.addMovableElement(removeElement, Sprite_MovableGlobalElement.MOVE_TYPE_BACK, success);
		}else if(removeCount > 0){
			success = BattleManager.removeGlobalState(removeId, removeCount);
			BattleManager.requestElementSpritesUpdate(removeElement);
			BattleManager.addMovableElement(removeElement, Sprite_MovableGlobalElement.MOVE_TYPE_BACK, success);
		}
	}
};

Game_Action.prototype.getAddGlobalStateId = function(){
	var item = this.item();
	if(!!item)
		return item.addGlobalStateId;
	else
		return 0;
};

Game_Action.prototype.getAddGlobalStateCount = function(){
	var item = this.item();
	if(!!item)
		return item.addGlobalCount;
	else
		return 0;
};

Game_Action.prototype.getRemoveGlobalStateId = function(){
	var item = this.item();
	if(!!item)
		return item.removeGlobalStateId;
	else
		return 0;
};

Game_Action.prototype.getRemoveGlobalStateCount = function(){
	var item = this.item();
	if(!!item)
		return item.removeGlobalCount;
	else
		return 0;
};

Game_Action.prototype.isRemoveGlobalCompletely = function(){
	var item = this.item();
	if(!!item && item.removeGlobalStateId > 0)
		return item.removeGlobalCompletely;
	else
		return false;
};

//---------------------------
//          Game_Interpreter
//---------------------------
CP.GlobalManager.PLUGIN_COMMAND = Game_Interpreter.prototype.pluginCommand;
Game_Interpreter.prototype.pluginCommand = function(command, args) {
	CP.GlobalManager.PLUGIN_COMMAND.call(this, command, args);

	if($gameParty.inBattle() && command == 'GlobalState'){
		var action = args[0];
		var stateId = Number(args[1]) || 0;
		var count = !!args[2] && args[2].toUpperCase() === "ALL" ? -1 : Number(args[2]) || 1;
		var elementId = CP.GlobalManager.getGlobalElement(stateId);
		var success = false;
		if(count > 0){
			if(action.toUpperCase() == "ADD"){
				success = BattleManager.addGlobalState(stateId, count);
				BattleManager.addMovableElement(elementId, Sprite_MovableGlobalElement.MOVE_TYPE_FORWARD, success);
			}else if(action.toUpperCase() == "REMOVE"){
				success = BattleManager.removeGlobalState(stateId, count);
				BattleManager.requestElementSpritesUpdate(elementId);
				BattleManager.addMovableElement(elementId, Sprite_MovableGlobalElement.MOVE_TYPE_BACK, success);
			}
		}else if(count === -1 && action.toUpperCase() == "REMOVE"){
			success = BattleManager.removeGlobalStateCompletely(stateId);
			BattleManager.requestElementSpritesUpdate(elementId);
			BattleManager.addMovableElement(elementId, Sprite_MovableGlobalElement.MOVE_TYPE_BACK, success);
		}
	}
};

//---------------------------
//          Game_Switches
//---------------------------
CP.GlobalManager.SWITCHES_ON_CHANGE = Game_Switches.prototype.onChange;
Game_Switches.prototype.onChange = function(){
	CP.GlobalManager.SWITCHES_ON_CHANGE.call(this);
	if($gameParty.inBattle())
		BattleManager.requestGlobalStatesChange();
};

//---------------------------
//          Game_Variables
//---------------------------
CP.GlobalManager.VARIABLES_ON_CHANGE = Game_Variables.prototype.onChange;
Game_Variables.prototype.onChange = function(){
	CP.GlobalManager.VARIABLES_ON_CHANGE.call(this);
	if($gameParty.inBattle())
		BattleManager.requestGlobalStatesChange();
};

//----------------------------
//          Window_BattleItem
//-----------------------------
CP.GlobalManager.BATTLE_ITEM_INCLUDES = Window_BattleItem.prototype.includes;
Window_BattleItem.prototype.includes = function(item) {
    var result = CP.GlobalManager.BATTLE_ITEM_INCLUDES.call(this, item);

    if(item && item.globalElements && item.globalElements.length > 0)
    	result = true;

    return result;
};

//---------------------------
//    Sprite_GlobalElementBase
//---------------------------
function Sprite_GlobalElementBase(){
	this.initialize.apply(this, arguments);
};

Sprite_GlobalElementBase.prototype = Object.create(Sprite_Base.prototype);
Sprite_GlobalElementBase.prototype.constructor = Sprite_GlobalElementBase;

Sprite_GlobalElementBase.prototype.initialize = function(elementId){
	this._elementId = elementId;
	Sprite_Base.prototype.initialize.call(this);
	this.setupElementData();
	this.requestChange(); //构造之后马上请求刷新
};

//请求刷新，如果不需要刷新的情况，空函数
Sprite_GlobalElementBase.prototype.requestChange = function(){};

//精灵是否已请求刷新，默认完全不处理
Sprite_GlobalElementBase.prototype.isChangeRequested = function(){
	return false;
};

//绘制完成时，恢复请求状态
Sprite_GlobalElementBase.prototype.resetChange = function(){};

//读取当前的元素data对象
Sprite_GlobalElementBase.prototype.elementData = function(){
	return CP.GlobalManager.getGlobalElementById(this._elementId);
};

Sprite_GlobalElementBase.prototype.setupElementData = function(){
	var element = this.elementData();
	if(!!element)
		this.setupElementDataAll(element);
};

Sprite_GlobalElementBase.prototype.setupElementDataAll = function(element){
	this.setupBitmap(element);
	this.setupAnchor(element);
	this.setupPosition(element);
};

Sprite_GlobalElementBase.prototype.setupBitmap = function(element){
	this.bitmap = element.image;
};

Sprite_GlobalElementBase.prototype.setupAnchor = function(element){
	this.anchor.set(element.anchorX, element.anchorY);
};

Sprite_GlobalElementBase.prototype.setupPosition = function(element){
	this.move(element.posX.call(this, element.id), element.posY.call(this, element.id));
};

Sprite_GlobalElementBase.prototype.update = function(){
	Sprite_Base.prototype.update.call(this);
	this.updateElementChange();
};

Sprite_GlobalElementBase.prototype.updateElementChange = function(){
	if(this.isChangeRequested()){
		this.refreshAll();
		this.resetChange();
	}
};

//刷新主函数
Sprite_GlobalElementBase.prototype.refreshAll = function(){
	this.changeElementVisibilty();
};

//变换元素精灵的可见性
Sprite_GlobalElementBase.prototype.changeElementVisibilty = function(){
	var ev = this.isElementVisibility();
	if(this.visible && !ev)
		this.hide();
	else if(!this.visible && ev)
		this.show();
};

Sprite_GlobalElementBase.prototype.isElementVisibility = function(){
	return true;
};

//---------------------------
//    Sprite_GlobalElement
//---------------------------
function Sprite_GlobalElement(){
	this.initialize.apply(this, arguments);
};

Sprite_GlobalElement.prototype = Object.create(Sprite_GlobalElementBase.prototype);
Sprite_GlobalElement.prototype.constructor = Sprite_GlobalElement;

Sprite_GlobalElement.prototype.initialize = function(elementId){
	Sprite_GlobalElementBase.prototype.initialize.call(this, elementId);
};

Sprite_GlobalElement.prototype.setupElementDataAll = function(element){
	Sprite_GlobalElementBase.prototype.setupElementDataAll.call(this, element);
	this.setupTextData(element);
};

Sprite_GlobalElement.prototype.setupTextData = function(element){
	if(!this._textSprite){
		this._textSprite = new Sprite_GlobalElement.Sprite_Text(this.bitmap.width + 24, this.bitmap.height + 24);
		this.addChild(this._textSprite);
	}

	this._textSprite.setFontFace(CP.GlobalManager.GLOBAL_ELEMENT_TEXT_DATA.font);
	this._textSprite.setFontSize(CP.GlobalManager.GLOBAL_ELEMENT_TEXT_DATA.size);
	this._textSprite.changeTextColor(element.countColor);
};

//精灵是否已请求刷新
Sprite_GlobalElement.prototype.isChangeRequested = function(){
	return BattleManager.isElementSpriteUpdateRequested(this._elementId);
};

Sprite_GlobalElement.prototype.requestChange = function(){
	BattleManager.requestElementSpritesUpdate(this._elementId);
};

//绘制完成时，恢复请求状态
Sprite_GlobalElement.prototype.resetChange = function(){
	BattleManager.resetElementSpritesUpdate(this._elementId);
};

//当前战场元素的默认层数，作为精灵是否可见的条件以及绘制内容
Sprite_GlobalElement.prototype.elementCount = function(){
	return BattleManager.globalElementCount(this._elementId);
};

//update部分
//刷新主函数
Sprite_GlobalElement.prototype.refreshAll = function(){
	Sprite_GlobalElementBase.prototype.refreshAll.call(this);
	this.refreshText();
};


Sprite_GlobalElement.prototype.isElementVisibility = function(){
	return this.elementCount() > 0;
};

Sprite_GlobalElement.prototype.refreshText = function(){
	this._textSprite.clear();
	this.drawAllCount();
};

Sprite_GlobalElement.prototype.drawAllCount = function(){
	var element = this.elementData();
	if(!!element){
		var tx = element.countX.call(this, element.id);
		var ty = element.countY.call(this, element.id);
		var text = CP.GlobalManager.GLOBAL_ELEMENT_TEXT_DATA.text.format(this.elementCount());
		this._textSprite.drawText(text, tx, ty, this.bitmap.width);
	}
};

//---------------------------
// Sprite_GlobalElement.Sprite_Text
// 战斗元素内部类，文字绘制
//---------------------------
Sprite_GlobalElement.Sprite_Text = function(){
	this.initialize.apply(this, arguments);
};

Sprite_GlobalElement.Sprite_Text.prototype = Object.create(Sprite_Base.prototype);
Sprite_GlobalElement.Sprite_Text.prototype.constructor = Sprite_GlobalElement.Sprite_Text;

Sprite_GlobalElement.Sprite_Text.prototype.initialize = function(width, height){
	Sprite_Base.prototype.initialize.call(this);
	this.bitmap = new Bitmap(width, height);
	this.move(0, 0);
};

Sprite_GlobalElement.Sprite_Text.prototype.clear = function(){
	this.bitmap.clear();
};

Sprite_GlobalElement.Sprite_Text.prototype.setFontFace = function(fontFace){
	this.bitmap.fontFace = fontFace;
};

Sprite_GlobalElement.Sprite_Text.prototype.setFontSize = function(size){
	this.bitmap.fontSize = size;
};

Sprite_GlobalElement.Sprite_Text.prototype.changeTextColor = function(color){
	this.bitmap.textColor = color;
};

Sprite_GlobalElement.Sprite_Text.prototype.drawText = function(text, x, y, maxWidth, align){
	if(align ===  undefined)
		align = "left";

	this.bitmap.drawText(text, x, y, maxWidth, this.bitmap.fontSize + 10, align);
};

//---------------------------
// Sprite_MovableGlobalElement
// 可以动的，做移动动画
//---------------------------
function Sprite_MovableGlobalElement(){
	this.initialize.apply(this, arguments);
};

Sprite_MovableGlobalElement.MOVE_TYPE_FORWARD = 1; //前进，从起点到元素位
Sprite_MovableGlobalElement.MOVE_TYPE_BACK = 2; //返回，从元素位返回起点

Sprite_MovableGlobalElement.prototype = Object.create(Sprite_GlobalElementBase.prototype);
Sprite_MovableGlobalElement.prototype.constructor = Sprite_MovableGlobalElement;

Sprite_MovableGlobalElement.prototype.initialize = function(elementId, moveType){
	this._duration = 0; //运动帧数
	this._stoped = false; //停止标记
	this._targetX = null;
	this._targetY = null;
	this._targetOpacity = null;
	this._moveType = moveType;
	Sprite_GlobalElementBase.prototype.initialize.call(this, elementId);
};

Sprite_MovableGlobalElement.prototype.hasStoped = function(){
	return !!this._stoped;
};

Sprite_MovableGlobalElement.prototype.isForward = function(){
	return this._moveType === Sprite_MovableGlobalElement.MOVE_TYPE_FORWARD;
};

Sprite_MovableGlobalElement.prototype.isBack = function(){
	return this._moveType === Sprite_MovableGlobalElement.MOVE_TYPE_BACK;
};

Sprite_MovableGlobalElement.prototype.setupElementDataAll = function(element){
	Sprite_GlobalElementBase.prototype.setupElementDataAll.call(this, element);
	this.setupOpacity(element);
}

Sprite_MovableGlobalElement.prototype.setupPosition = function(element){
	if(this.isForward())
		this.setupHomePosition(element);
	else if(this.isBack())
		Sprite_GlobalElementBase.prototype.setupPosition.call(this, element);
};

Sprite_MovableGlobalElement.prototype.setupHomePosition = function(element){
	var x = CP.GlobalManager.GLOBAL_ELEMENT_HOME_POSITION.x.call(this, element.id);
	var y = CP.GlobalManager.GLOBAL_ELEMENT_HOME_POSITION.y.call(this, element.id);
	this.move(x, y);
};

Sprite_MovableGlobalElement.prototype.setupOpacity = function(element){
	if(this.isForward())
		this.opacity = CP.GlobalManager.GLOBAL_ELEMENT_OPACITY_MIN;
	else
		this.opacity = 255;
};

Sprite_MovableGlobalElement.prototype.targetX = function(){
	var element = this.elementData();
	if(this.isForward())
		return element.posX.call(this, element.id);
	else if(this.isBack())
		return CP.GlobalManager.GLOBAL_ELEMENT_HOME_POSITION.x.call(this, element.id);
	else
		return null;
};

Sprite_MovableGlobalElement.prototype.targetY = function(){
	var element = this.elementData();
	if(this.isForward())
		return element.posY.call(this, element.id);
	else if(this.isBack())
		return CP.GlobalManager.GLOBAL_ELEMENT_HOME_POSITION.y.call(this, element.id);
	else
		return null;
};

Sprite_MovableGlobalElement.prototype.targetOpacity = function(){
	if(this.isForward())
		return 255;
	else if(this.isBack())
		return CP.GlobalManager.GLOBAL_ELEMENT_OPACITY_MIN;
};

//开始移动
Sprite_MovableGlobalElement.prototype.startMove = function(duration){
	this._targetX = this.targetX();
	this._targetY = this.targetY();
	this._targetOpacity = this.targetOpacity();
	this._duration = duration;
};

Sprite_MovableGlobalElement.prototype.stopMove = function(){
	this._targetX = null;
	this._targetY = null;
	this._targetOpacity = null;
	this._duration = 0;
	this._stoped = true;
};

Sprite_MovableGlobalElement.prototype.update = function(){
	Sprite_GlobalElementBase.prototype.update.call(this);
	this.updateMovement();
};

Sprite_MovableGlobalElement.prototype.isMoving = function(){
	return this._duration > 0 && this._targetX !== null && this._targetY !== null;
};

Sprite_MovableGlobalElement.prototype.updateMovement = function(){
	if(this.isMoving())
		this.updatePosition();
	else{
		this.requestMainElementspriteChange();
		this.stopMove();
	}
};

Sprite_MovableGlobalElement.prototype.updatePosition = function(){
	this.x = (this.x * (this._duration - 1) + this._targetX) / this._duration;
	this.y = (this.y * (this._duration - 1) + this._targetY) / this._duration;
	this.opacity = (this.opacity * (this._duration - 1) + this._targetOpacity) / this._duration;
	this._duration--;
};

Sprite_MovableGlobalElement.prototype.requestMainElementspriteChange = function(){
	var element = this.elementData();
	if(!!element && element.id > 0)
		BattleManager.requestElementSpritesUpdate(element.id);
};

//---------------------------
//    Scene_Battle
//---------------------------
CP.GlobalManager.SCENE_BATTLE_CREATE_DISPLAY_OBJECTS = Scene_Battle.prototype.createDisplayObjects;
Scene_Battle.prototype.createDisplayObjects = function(){
	CP.GlobalManager.SCENE_BATTLE_CREATE_DISPLAY_OBJECTS.call(this);
	this.initMoveableElementSpriteList();
	this.createAllGlobalElementSprites();
};

Scene_Battle.prototype.createAllGlobalElementSprites = function(){
	this._globalElementSprites = {};
	for(var i = 0; i < CP.GlobalManager.GLOBAL_ELEMENT_LIST.length; i++){
		var element = CP.GlobalManager.GLOBAL_ELEMENT_LIST[i];
		this._globalElementSprites[element.id] = new Sprite_GlobalElement(element.id);
		this.addChild(this._globalElementSprites[element.id]);
	}
};

Scene_Battle.prototype.initMoveableElementSpriteList = function(){
	this._movableElementSprites = [];
};

CP.GlobalManager.SCENE_BATTLE_UPDATE = Scene_Battle.prototype.update;
Scene_Battle.prototype.update = function(){
	CP.GlobalManager.SCENE_BATTLE_UPDATE.call(this);
	this.updateMovableElementSprites();
};

Scene_Battle.prototype.updateMovableElementSprites = function(){
	this.updateMovableElementSpritesAdd();
	this.updateMovableElementSpritesRemove();
};

Scene_Battle.prototype.updateMovableElementSpritesAdd = function(){
	BattleManager.allMovableElements().forEach(function(data){
		if(data.elementId > 0){
			var sprite = new Sprite_MovableGlobalElement(data.elementId, data.moveType);
			this._movableElementSprites.push(sprite);
			this.addChild(sprite);
			sprite.startMove(CP.GlobalManager.GLOBAL_ELEMENT_MOVE_TIME);
		}
	}, this);
	BattleManager.resetMovableElements();
};

Scene_Battle.prototype.updateMovableElementSpritesRemove = function(){
	for(var i = 0; i < this._movableElementSprites.length; i++){
		var sprite = this._movableElementSprites[i];
		if(this.canMovableElementSpriteRemove(sprite)){
			this.removeChild(sprite);
			this._movableElementSprites[i] = null;
		}
	}
	this._movableElementSprites = this._movableElementSprites.filter((sprite) => !!sprite);
};

Scene_Battle.prototype.canMovableElementSpriteRemove = function(sprite){
	if(!sprite)
		return false;
	if(!sprite.hasStoped())
		return false;
	if(sprite.isForward()){
		var element = sprite.elementData();
		if(element && element.id > 0){
			var mainSprite = this._globalElementSprites[element.id];
			if(!!mainSprite && mainSprite.visible)
				return true;
			else
				return false;
		}else
			return false;
	}else if(sprite.isBack())
		return true;
	else
		return false;
};

//元素移动的时候，阻塞战斗
CP.GlobalManager.SCENE_BATTLE_IS_BUSY = Scene_Battle.prototype.isBusy;
Scene_Battle.prototype.isBusy = function(){
	if(this.hasAnyMovableElementSpriteMoving())
		return true;
	else
		return CP.GlobalManager.SCENE_BATTLE_IS_BUSY.call(this);
};

Scene_Battle.prototype.hasAnyMovableElementSpriteMoving = function(){
	if(this._movableElementSprites.length <= 0)
		return false;
	else
		return this._movableElementSprites.some((sprite) => sprite.isMoving());
};